/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { xmlParse, xsltProcess, xpathParse, ExprContext } from "./xslt_processor.js";

const originTextXML =
  "<all>" +
  '<item pos="2">A 三方库组件 Ba bộ phận thư viện</item>' +
  '<item pos="3">B مكونات مستودع ثلاثية</item>' +
  '<item pos="1">C ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789</item>' +
  "</all>";
const originTextXSL =
  "<xsl:stylesheet>" +
  '<xsl:template match="/">' +
  '<xsl:for-each select="//item">' +
  '<xsl:sort select="@pos"/>' +
  '<xsl:value-of select="."/>' +
  "</xsl:for-each>" +
  "</xsl:template>" +
  "</xsl:stylesheet>";
const originHTMLXML = ` <?xml version="1.0" encoding="ISO-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="cdcataprint.xsl"?>
    <cataprint>
    <cd>
    <title>Empire Burlesque 三方库组件 Ba bộ phận thư viện</title>
    <artist>Bob Dylan مكونات مستودع ثلاثية ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <year>1985</year>
    </cd>
    .
    .
    </cataprint>`;
const originHTMLXSL = ` <?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<xsl:for-each select="cataprint/cd">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>

</xsl:stylesheet> `;
const variablesXSLTString = `<?xml version="1.0"?>
    <xsl:stylesheet version="1.0">
    <xsl:template match="test">
        <span> <xsl:value-of select="$test" /> </span>
    </xsl:template>
    <xsl:template match="root">
        <xsl:element name="{local-name()}">
        <xsl:apply-templates select="test"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="/">
        <xsl:apply-templates select="root"/>
    </xsl:template>
    </xsl:stylesheet>`;
const xpathXML = [
  "<page>",
  "<request>",
  "<q>new york</q>",
  "</request>",
  '<location lat="100" lon="200"/>',
  "</page>",
].join("");



// ParseXML
function xmlParse_test() {
  let originXMLObj;
  let startTime = Date.now();
  for (let i = 0; i < 1000; i++) {
    originXMLObj = xmlParse(originTextXML);
    // print(
    //   "The original XML root node contains" +
    //     originXMLObj.childNodes[0].childNodes.length +
    //     "child nodes"
    // );
  }
  let endTime = Date.now();
  if (!areEqual(originXMLObj.childNodes[0].childNodes.length, 3)) {
    throw new Error('xmlParse_test failed');
  }
  print(`xslt_processor_test_xmlParese: ${endTime - startTime} ms`);
}

// XSLT to HTML
function xsltProcess_Test() {
  let html;
  let expectValue = '<html><body><h2>My CD Collection</h2><table border="1"><tr bgcolor="#9acd32"><th>Title</th><th>Artist</th></tr><tr><td>Empire Burlesque 三方库组件 Ba bộ phận thư viện</td><td>Bob Dylan مكونات مستودع ثلاثية ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789</td></tr></table></body></html>';
  let originXMLObj = xmlParse(originHTMLXML);
  let originXSLObj = xmlParse(originHTMLXSL);
  let startTime = Date.now();
  for (let i = 0; i < 1000; i++) {
    html = xsltProcess(originXMLObj, originXSLObj);
    // print("result:" + html);
  }
  let endTime = Date.now();
  if (!areEqual(html, expectValue)) {
    throw new Error('xsltProcess_Test_01 failed');
  }
  print(`xslt_processor_test_xmlProcess: ${endTime - startTime} ms`);
}


// Xpath calculating expressions/page/location/@lat
function xpathParse_Test() {
  let expr1;
  const locationParam = "location";
  const latParam = "lat";
  const xpathExpr = `/page/${locationParam}/@${latParam}`;
  let startTime = Date.now();
  for (let i = 0; i < 100000; i++) {
    expr1 = xpathParse(xpathExpr);
    // print("The current node attribute is:" + nodeSet[0].nodeName + "=" + nodeSet[0].nodeValue);
  }
  let endTime = Date.now();
  const ctx = new ExprContext(xmlParse(xpathXML));
  const result = expr1.evaluate(ctx);
  const nodeSet = result.nodeSetValue();
  if (!areEqual(nodeSet[0].nodeName, "lat")) {
    throw new Error('xpathParse_Test failed');
  }
  if (!areEqual(nodeSet[0].nodeValue, "100")) {
    throw new Error('xpathParse_Test failed');
  }
  print(`xslt_processor_test_xmlXpath: ${endTime - startTime} ms`);
}

// Xpath calculating expressions/page/location/@lat
function exprContext_Test() {
  let nodeSet;
  let startTime = Date.now();
  const locationParam = "location";
  const latParam = "lat";
  const xpathExpr = `/page/${locationParam}/@${latParam}`;
  const expr1 = xpathParse(xpathExpr);
  let ctx;
  for (let i = 0; i < 1000; i++) {
    ctx = new ExprContext(xmlParse(xpathXML));
    // print("The current node attribute is:" + nodeSet[0].nodeName + "=" + nodeSet[0].nodeValue);
  }
  let endTime = Date.now();
  const result = expr1.evaluate(ctx);
    nodeSet = result.nodeSetValue();
  if (!areEqual(nodeSet[0].nodeName, "lat")) {
    throw new Error('exprContext_Test failed');
  }
  if (!areEqual(nodeSet[0].nodeValue, "100")) {
    throw new Error('exprContext_Test failed');
  }
  print(`xslt_processor_test_xmlExprContext: ${endTime - startTime} ms`);
}

// Xpath calculating expressions/page
function evaluate_Test() {
  let e;
  const xpathExpr = "/page";
  const expr1 = xpathParse(xpathExpr);
  const ctx = new ExprContext(xmlParse(xpathXML));
  let startTime = Date.now();
  for (let i = 0; i < 10000; i++) {
    e = expr1.evaluate(ctx);
  }
  let endTime = Date.now();
  let nodeSet = e.nodeSetValue();
  if (!areEqual(nodeSet.length, 1)) {
    throw new Error('evaluate_Test failed');
  }
  print(`xslt_processor_test_xmlEvaluate: ${endTime - startTime} ms`);
}

// Expected results and actual results verification 
function areEqual(expected, actual) {
  // If expected and actual are both NaN, consider them equal.
  if (expected === actual || expected !== expected && actual !== actual) {
      return true
  } else {
      return false
  }
}

xmlParse_test();
xsltProcess_Test();
xpathParse_Test();
exprContext_Test();
evaluate_Test();